﻿using LitJson;
using System.Collections.Generic;

namespace Devil.Persistent
{
    public struct PersistentReference<T> : System.IEquatable<PersistentReference<T>> where T : class, ISharedInstance
    {
        T mInstance;

        public bool Equals(PersistentReference<T> other)
        {
            return mInstance == null ? other.mInstance == null : mInstance.Equals(other.mInstance);
        }

        public override bool Equals(object obj)
        {
            if (obj is PersistentReference<T> refInst)
                return mInstance == null ? refInst.mInstance == null : mInstance.Equals(refInst.mInstance);
            else
                return mInstance == null ? obj == null : mInstance.Equals(obj);
        }

        public override int GetHashCode()
        {
            return mInstance == null ? 0 : mInstance.GetHashCode();
        }

        public override string ToString()
        {
            return mInstance == null ? $"Reference<{typeof(T).Name}>" : mInstance.ToString();
        }

        public static bool operator ==(PersistentReference<T> a, PersistentReference<T> b)
        {
            return a.mInstance == b.mInstance;
        }

        public static bool operator !=(PersistentReference<T> a, PersistentReference<T> b)
        {
            return a.mInstance != b.mInstance;
        }

        public static implicit operator T(PersistentReference<T> refInst)
        {
            return refInst.mInstance;
        }

        public static implicit operator PersistentReference<T>(T inst)
        {
            PersistentReference<T> refinst;
            refinst.mInstance = inst;
            return refinst;
        }

        public static JsonData Serialize(PersistentReference<T> refInst)
        {
            return PersistentSystem.Instance?.SerializeReference(refInst.mInstance);
        }

        public static PersistentReference<T> Deserialize(JsonData dt)
        {
            PersistentReference<T> refinst;
            refinst.mInstance = PersistentSystem.Instance?.DeserializeReference(dt) as T;
            return refinst;
        }
    }

    public partial class PersistentSystem
    {
        abstract class RwCmd
        {
            internal abstract IPersistentBlock GetBlock(object instance);
            internal abstract object GetInstance(string blockName, int instanceId);
        }

        // 当前执行的读写指令
        readonly List<RwCmd> mRwCmds = new List<RwCmd>(2);

        public JsonData SerializeReference(ISharedInstance instance)
        {
            if (instance == null)
                return null;
            lock (mRwCmds)
            {
                if (mRwCmds.Count == 0)
                    throw new System.InvalidOperationException("You can only serialize reference during saving command.");
                for (int i = mRwCmds.Count - 1; i >= 0; i--)
                {
                    var block = mRwCmds[i].GetBlock(instance);
                    if (block != null)
                    {
                        var obj = new JsonData();
                        obj["block"] = block.BlockName;
                        obj["id"] = instance.InstanceId;
                        return obj;
                    }
                }
            }
            return null;
        }

        public object DeserializeReference(JsonData data)
        {
            if (data == null || !data.IsObject)
                return null;
            var blockName = (string)data["block"];
            if (string.IsNullOrEmpty(blockName))
                return null;
            var id = (int)data["id"];
            lock (mRwCmds)
            {
                if (mRwCmds.Count == 0)
                    throw new System.InvalidOperationException("You can only deserialize reference during loading command.");
                for (int i = mRwCmds.Count - 1; i >= 0; i--)
                {
                    var obj = mRwCmds[i].GetInstance(blockName, id);
                    if (obj != null)
                        return obj;
                }
            }
            return null;
        }

    }
}
